<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="tLl1M" id="tLl1M"><span data-lake-id="u8236cf5c" id="u8236cf5c">典型回答</span></h1>
  <p data-lake-id="udc615902" id="udc615902"><br></p>
  <p data-lake-id="u8ec13e91" id="u8ec13e91"><span data-lake-id="ub5b6eea0" id="ub5b6eea0">上下文切换是指 CPU 从一个线程转到另一个线程时，需要保存当前线程的上下文状态，恢复另一个线程的上下文状态，以便于下一次恢复执行该线程时能够正确地运行。</span></p>
  <p data-lake-id="ub8171249" id="ub8171249"><span data-lake-id="uf3bf0e48" id="uf3bf0e48">​</span><br></p>
  <p data-lake-id="ub09df306" id="ub09df306"><span data-lake-id="u5a4aef7b" id="u5a4aef7b">在多线程编程中，上下文切换是一种常见的操作，上下文切换通常是指在一个 CPU 上，由于多个线程共享 CPU 时间片，当一个线程的时间片用完后，需要切换到另一个线程运行。此时需要保存当前线程的状态信息，包括程序计数器、寄存器、栈指针等，以便下次继续执行该线程时能够恢复到正确的执行状态。同时，需要将切换到的线程的状态信息恢复，以便于该线程能够正确运行。</span></p>
  <p data-lake-id="uca2313ea" id="uca2313ea"><span data-lake-id="u54c3a8e0" id="u54c3a8e0">​</span><br></p>
  <p data-lake-id="u88867541" id="u88867541"><strong><span data-lake-id="u633b3f97" id="u633b3f97">在多线程中，上下文切换的开销比单线程大，因为在多线程中，需要保存和恢复更多的上下文信息。过多的上下文切换会降低系统的运行效率，因此需要尽可能减少上下文切换的次数。</span></strong></p>
  <p data-lake-id="ufbbb2370" id="ufbbb2370"><strong><span data-lake-id="u3e61638d" id="u3e61638d">​</span></strong><br></p>
  <h1 data-lake-id="Sk18S" id="Sk18S"><span data-lake-id="u72f296d1" id="u72f296d1">扩展知识</span></h1>
  <p data-lake-id="u8be32a4e" id="u8be32a4e"><br></p>
  <h2 data-lake-id="HO3rG" id="HO3rG"><span data-lake-id="u50cc1ca4" id="u50cc1ca4">减少上下文切换</span></h2>
  <p data-lake-id="u66c789f7" id="u66c789f7"><br></p>
  <p data-lake-id="ud36f1645" id="ud36f1645"><span data-lake-id="u709a0c70" id="u709a0c70">频繁的上下文切换会导致CPU时间的浪费，因此在多线程编程时需要尽可能地避免它。以下是一些避免频繁上下文切换的方法：</span></p>
  <p data-lake-id="u2c4364d7" id="u2c4364d7"><span data-lake-id="uca3b4a6c" id="uca3b4a6c">​</span><br></p>
  <ol list="u9cfa63fb">
   <li fid="ueeb76962" data-lake-id="u2e8e010a" id="u2e8e010a"><span data-lake-id="u726e2336" id="u726e2336">减少线程数：可以通过合理的线程池管理来减少线程的创建和销毁，线程数不是越多越好，合理的线程数可以避免线程过多导致上下文切换。</span></li>
  </ol>
  <p data-lake-id="ud883128f" id="ud883128f"><br></p>
  <ol list="u9cfa63fb" start="2">
   <li fid="ueeb76962" data-lake-id="u3b1e4f6d" id="u3b1e4f6d"><span data-lake-id="u77362158" id="u77362158">使用无锁并发编程：无锁并发编程可以避免线程因等待锁而进入阻塞状态，从而减少上下文切换的发生。</span></li>
  </ol>
  <p data-lake-id="uf753997f" id="uf753997f"><br></p>
  <ol list="u9cfa63fb" start="3">
   <li fid="ueeb76962" data-lake-id="ubb585966" id="ubb585966"><span data-lake-id="uaf8ed31a" id="uaf8ed31a">使用CAS算法：CAS算法可以避免线程的阻塞和唤醒操作，从而减少上下文切换。</span></li>
  </ol>
  <p data-lake-id="ubd75982a" id="ubd75982a"><br></p>
  <ol list="u9cfa63fb" start="4">
   <li fid="ueeb76962" data-lake-id="u51a0eb87" id="u51a0eb87"><span data-lake-id="u1b8dcd1f" id="u1b8dcd1f">使用协程（JDK 19的虚拟线程）：协程是一种用户态线程，其切换不需要操作系统的参与，因此可以避免上下文切换。（避免的是操作系统级别的上下文切换，但是仍然需要在JVM层面做一些保存和恢复线程的状态，但是也成本低得多）</span></li>
  </ol>
  <p data-lake-id="u3840ef62" id="u3840ef62"><br></p>
  <ol list="u9cfa63fb" start="5">
   <li fid="ueeb76962" data-lake-id="u4ef5150f" id="u4ef5150f"><span data-lake-id="u6c4b348a" id="u6c4b348a">合理地使用锁：在使用锁的过程中，需要避免过多地使用同步块或同步方法，尽量缩小同步块或同步方法的范围，从而减少线程的等待时间，避免上下文切换的发生。</span></li>
  </ol>
 </body>
</html>